from market.models import UserProfile, BetRoom, Player, Strategy, Fund, WebSiteComment
from market.models import Asset, History, PlayerPortfolioForHistory
from market.models import DigitalContract, BidOnContract, OfferOnContract, LiquidityToken, TradedContract, LastVisitedContract
from market.authentification import authentificatePlayer, authentificateUser, authentificateUserWithBetroom
from market.marketData import MarketData
from market.view import View
from market.strategyAndFundHelper import isFixedStrat, getFundMtM, getPercOnAssetInStrat, getPortfolioMtM
from django.utils import simplejson
from market.cometHelper import getChatRoomPlayerStatus
from datetime import datetime, date, time
import itertools
import operator


###########################################################################################
# returns the betrooms the user is betting in
def getBetroomsToPlay(request):
        return { 'betrooms':[{ 'name': p.mainStrategy.betroom.name } for p in Player.objects.filter( userBeingThisPlayer = request.user, mainStrategy__betroom__status__gte = 1 ) ] }
        
###########################################################################################
# returns the betrooms the user is administrating in
def getBetroomsToAdmin(request):
        return { 'betrooms':[{ 'name': b.name } for b in BetRoom.objects.filter( personInCharge = request.user ) ] }

###########################################################################################
# returns the betrooms being launched
def getBetroomsBeingLaunched(request):
        return { 'betrooms':[{ 'name': b.name } for b in BetRoom.objects.filter( status = 0 ) ] }

###########################################################################################
# returns the betrooms description
def getBetroomDescription(request):
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificateUser( request, alternative_response_list ) ):
                return alternative_response_list[0]
        return { 'description': BetRoom.objects.get( name = request.user.get_profile().nameOfTheLastVistedBetRoom ).description }


#######################################################################################
#return the market views
def getMarketView(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        m = MarketData(player_list[0].dbPlayer.mainStrategy.betroom);
	v = m.getMarketView()
	return v.toDictionary()

#######################################################################################
# return the market prices
def getMarketPrices(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        m = MarketData(player_list[0].dbPlayer.mainStrategy.betroom);
	v = m.getMarketView()
	return { 'priceList':[{ 'assetName':d[0].name, 'price':m.getAssetPrice(d[0])} for d in v.getFullView()]}

        

#######################################################################################
#keep djando happy (suppress and try to access /Admin/)
def getAssets(request):

        betroom=[]
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        player_list =[]
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                alternative_response_list = [] 
                if not( authentificateUserWithBetroom( request, betroom, alternative_response_list ) ):
                        return alternative_response_list[0]
        else:
                betroom.append(player_list[0].dbPlayer.mainStrategy.betroom)


        try:
                includeNonStdStr = str(request.POST['includeNonStd'])
        except:
                try:
                        includeNonStdStr = str(request.GET['includeNonStd'])
                except:
                        includeNonStdStr = "False"
        
        
        if includeNonStdStr.lower() == "true":
                includeNonStd = True
        else:
                includeNonStd = False
        if includeNonStd:
                AssetList = Asset.objects.filter(isAvailableForStandardStrategy = True, betroom = betroom[0] )
        else:
                AssetList = Asset.objects.filter( isStandard = True, isAvailableForStandardStrategy = True, betroom = betroom[0] )
        
        return  { 'assets':[{ 'assetName':a.name, 'assetDescription':a.description } for a in AssetList] }
        
#######################################################################################
#keep djando happy (suppress and try to access /Admin/)
def getAssetsAll(request):
        betroom=[]
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificateUserWithBetroom( request, betroom, alternative_response_list ) ):
                        return alternative_response_list[0]

        return  { 'assets':[{ 'assetName':a.name,
                              'assetDescription':a.description,
                              'isStd':a.isStandard
                              }
                            for a in Asset.objects.filter( isAvailableForStandardStrategy = True, betroom = betroom[0] )],
                   'beroomStatus': betroom[0].status }


	
#######################################################################################
# helper for createPricesChartJson():
def getPrice( history, theAsset ):
	assetForHisto = history.assetforhistory_set.filter(asset= theAsset)
	if len(assetForHisto) == 1:
		return assetForHisto[0].price
	else:
		return

	
#######################################################################################
# return a dictionary with the history of prices per asset
# the player argument is just to fit to the signature of function call from getAllJsonsForTablesAndCharts
def getPricesHistory(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        
	sortedHisto =  [ h for h in History.objects.filter(betroom = player_list[0].dbPlayer.mainStrategy.betroom)]
	sortedHisto.sort(lambda a,b:cmp(a.time, b.time))
	assetList = [ afh.asset for afh in sortedHisto[len(sortedHisto)-1].assetforhistory_set.all()]

	tmp = { 'datesList':[{ 'time':h.time.strftime("%d %B %H:%M"),#str(h.time),
                             'assetsList':[{ 'name':asset.name,
                                             'price':getPrice( h, asset )
                                             } for asset in assetList]
                             } for h in sortedHisto ]
              }
	return tmp


#######################################################################################
# helper for createPricesChartJson():
def getMtM( history, player ):
	portfolioForHisto = PlayerPortfolioForHistory.objects.filter( history = history, player= player)
	if len(portfolioForHisto) == 1:
		return portfolioForHisto[0].portfolioMtM
	else:
		return
	
#######################################################################################
# return a dictionary with the history of mtm per player
# the player argument is just to fit to the signature of function call from getAllJsonsForTablesAndCharts
def getMtMsHistory(request):
	player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        
	sortedHisto =  [ h for h in History.objects.filter(betroom = player_list[0].dbPlayer.mainStrategy.betroom)]
	if len(sortedHisto) > 0:
                sortedHisto.sort(lambda a,b:cmp(a.time, b.time))
                playerList = [ pfh.player for pfh in PlayerPortfolioForHistory.objects.filter( history = sortedHisto[len(sortedHisto)-1] )]
                return { 'datesList':[{ 'time':h.time.strftime("%d %B %H:%M"),#str(h.time),
                             'playersList':[{ 'name':player.userBeingThisPlayer.username,
                                              'mtm':getMtM(h, player)
                                             } for player in playerList]
                             } for h in sortedHisto] }

	return {}
	
#######################################################################################
# return a json with the percentage (in mtm of asset) of the player
def getMainViewInMtMJson(request):

        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        p = player_list[0]
        
	m = MarketData(p.dbPlayer.mainStrategy.betroom)
	n = p.getMainFundTotalNumberOfAssets()
	stratView = View()
	stratView.setViewFromStrategy( p.dbPlayer.mainStrategy )
	totalValue = m.getStrategyMtM(stratView)
	assetList = [a for a in Asset.objects.filter(isAvailableForStandardStrategy=True)]
	mtmView = View( assets=assetList, probas=[ p.getNumberOfSpecifiedAssetInMainFund(a)*m.getMarketExpectation(a)/totalValue for a in assetList])
	return simplejson.dumps( mtmView.toDictionary() )
	


#######################################################################################
# return a json with the ranking in case of asset strike
# the player argument is just to fit to the signature of function call from getAllJsonsForTablesAndCharts
def getRankingTableData(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        

        m = MarketData(player_list[0].dbPlayer.mainStrategy.betroom)
        listPlayer = [ [p,getPortfolioMtM(p,m)] for p in Player.objects.filter(mainStrategy__betroom = player_list[0].dbPlayer.mainStrategy.betroom) ]
        listPlayer.sort(lambda a,b:cmp(a[1], b[1]), reverse=True)
        return { 'playerList':[{ 'name':r[0].userBeingThisPlayer.username, 'mtm':r[1]  } for r in listPlayer ] }


#######################################################################################
def getPerc( p, m, a, stratMtM):
        if stratMtM==0.:
                return 0.
        return p.getNumberOfSpecifiedAssetInMainFund(a)*m.getAssetPrice(a)/stratMtM
	
#######################################################################################
# return different information about the player main strategy to display in the website
def getPlayerMainViewData(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        p = player_list[0]
        
	n = p.getMainFundTotalNumberOfAssets()
	# market value of the strategy
	m = MarketData(player_list[0].dbPlayer.mainStrategy.betroom)
	stratMtM = getFundMtM( p.dbPlayer, m, p.dbPlayer.mainStrategy )
	tmp = { 'assetsList':[{ 'name':a.name,
                                'playerView':getPercOnAssetInStrat( p.dbPlayer.mainStrategy, a ),
                                'mtmPerc':getPerc( p, m, a, stratMtM),
                                'quantity':p.getNumberOfSpecifiedAssetInMainFund(a),
				'marketPrice':m.getAssetPrice(a),
				'value':p.getNumberOfSpecifiedAssetInMainFund(a)*m.getAssetPrice(a)
                             } for a in Asset.objects.filter( betroom = p.dbPlayer.mainStrategy.betroom, isAvailableForStandardStrategy=True) ]
              }
	return tmp
	
#######################################################################################
# return different information about the player main strategy to display in the website
def getPlayerMainViewData2(request):
        betroom=[]
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        player_list =[]
        dummy = False
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                alternative_response_list = [] 
                if not( authentificateUserWithBetroom( request, betroom, alternative_response_list ) ):
                        return alternative_response_list[0]
                else:
                        try:
                                player = Player.objects.get( mainStrategy__betroom = betroom[0], userBeingThisPlayer = request.user )
                        except:
                                dummy = True                        
        else:
                betroom.append(player_list[0].dbPlayer.mainStrategy.betroom)
                player = player_list[0].dbPlayer


        if dummy:
                return { 'assetsList':[] }
	return { 'assetsList':[{ 'name':a.name,
                                'playerView':getPercOnAssetInStrat( player.mainStrategy, a )
                             } for a in Asset.objects.filter( betroom = betroom[0], isAvailableForStandardStrategy=True)  ]
              }


#######################################################################################
# return the list of the player having registered to the betroom being launched
def getPlayerList(request):
        betroom=[]
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificateUserWithBetroom( request, betroom, alternative_response_list ) ):
                return alternative_response_list[0]                     

	tmp = { 'playersList':[{ 'name':p.userBeingThisPlayer.username } for p in Player.objects.filter( mainStrategy__betroom = betroom[0])  ] }
	tmp['betroomPwd'] = betroom[0].password
	return tmp


	
#######################################################################################
# return a json with the (set and current) mtm repartition of the player
def getPlayerInvestementRepartition(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        p = player_list[0]
        m = MarketData(p.dbPlayer.mainStrategy.betroom)
        totalMtM = p.getPortfolioMtM( m )
        investedStratList = []
        uninvestedStratList = []
        for strat in Strategy.objects.filter(betroom = p.dbPlayer.mainStrategy.betroom ):
                
                isAlreadyInvested = False
                try:
                        fund = Fund.objects.get( player =p.dbPlayer, strategy = strat )
                        isAlreadyInvested = True
                except Fund.DoesNotExist:
                        if isFixedStrat( strat ):
                                uninvestedStratList.insert( 0, {'name':strat.name} )
                        else:
                                uninvestedStratList.append( {'name':strat.name} )
                if isAlreadyInvested:
                        stratValue = fund.numberOfAssetsInFund * m.getStrategyMtM(fund.strategy)
                        repTmp = 0
                        if totalMtM!= 0:
                                repTmp = stratValue/ totalMtM
                        dic = { 'name':fund.strategy.name,
                                'playerSetMtmRep':fund.fundTargetPercentageInPortfolio,
                                'playerNumOfAssetInStrat': fund.numberOfAssetsInFund,
                                'stratValue': stratValue,
                                'playerCurrentMtmRep': repTmp
                                }
                        ## we always set the main strategy on the first row
                        if fund.strategy == p.dbPlayer.mainStrategy:
                                investedStratList.insert( 0, dic )
                        else:
                                tmp = isFixedStrat( fund.strategy )
                                if tmp[0]: # we want the bank account in second position, (or at the beg if the main strat has not been added yet
                                        if len( investedStratList ) > 0:
                                                if investedStratList[0]['name'] == p.dbPlayer.mainStrategy.name:
                                                        investedStratList.insert( 1, dic )
                                        else:
                                                investedStratList.insert( 0, dic )
                                else:
                                        investedStratList.append( dic )

        tmp = { 'investedStrategyList':investedStratList, 'uninvestedStratList':uninvestedStratList }
	return tmp

	
#######################################################################################
# return a json with the comment  to dispplay and a field saying if the comment bellongs to the player
def getComments(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                res = { 'comments':[] }
        else:
                p = player_list[0]
                res = { 'comments':
                        [ {
                        'posterName':c.poster.userBeingThisPlayer.username,
                        'idNumber':c.id,
                        'postTime':c.postTime.strftime("%d %B %H:%M"),
                        'textValue':c.textValue,
                        'belongToPlayer': c.poster == p.dbPlayer
                        }
                        for c in WebSiteComment.objects.filter( isVisible = True, poster__mainStrategy__betroom = p.dbPlayer.mainStrategy.betroom )]
                        }
                #update the status
                playerStatus = getChatRoomPlayerStatus( p.dbPlayer )
                playerStatus.isUpToDateStatusForTheChat = True
                playerStatus.save()
        return res

#######################################################################################
# get all the contracts in the betroom
def getContracts(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        betroom = player_list[0].dbPlayer.mainStrategy.betroom
        return { 'contracts':[ {'name': c.name}  for c in DigitalContract.objects.filter( issuer__mainStrategy__betroom = betroom )] }
        
#######################################################################################
# get all the contracts not yet settled in the betroom
def getUnsettledContracts(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        betroom = player_list[0].dbPlayer.mainStrategy.betroom
        return { 'contracts':[ {'name': c.name}  for c in DigitalContract.objects.filter( issuer__mainStrategy__betroom = betroom, settlementStatus__lt = 0 )] }




#######################################################################################
# get the general information about the specified contract
def getSelectedContractGeneralInfo( contract, player ):

        # update the status  xhen expired
        if contract.expiry < datetime.now() and contract.settlementStatus == -2:
                contract.settlementSatus = -1
                contract.save()
                
        # liquidity token information
        liquidityToken = LiquidityToken.objects.get( offer__contract = contract )
        # last trades information
        tradedContractList = TradedContract.objects.filter( contract = contract ).order_by('tradeDate')
        numberOfTrades = len( tradedContractList )
        if numberOfTrades == 0:
                lastTradeDate = 'NA'
                lastTradePrice = 'NA'
        else:
                lastTradeDate = tradedContractList[numberOfTrades-1].tradeDate.strftime("%d/%m/%Y %H:%M")
                lastTradePrice = tradedContractList[numberOfTrades-1].tradedPrice

        # portfolio information
        contractsBoughtByPlayer = TradedContract.objects.filter( contract = contract, buyer = player )
        bmean = 0
        if len(contractsBoughtByPlayer) > 0:
                bmean = sum([ bc.tradedPrice for bc in contractsBoughtByPlayer ])/len(contractsBoughtByPlayer)
        contractsSoldByPlayer = TradedContract.objects.filter( contract = contract, seller = player )
        smean = 0
        if len(contractsSoldByPlayer) > 0:
                smean = sum([ sc.tradedPrice for sc in contractsSoldByPlayer ])/len(contractsSoldByPlayer)
        pAndLPay = len( contractsBoughtByPlayer ) * ( 100 - bmean ) +  len( contractsSoldByPlayer ) * ( smean - 100 )
        pAndLDoNotPay = len( contractsBoughtByPlayer ) * ( 0 - bmean ) + len( contractsSoldByPlayer ) * ( smean - 0 )
        realisedPandL = 0
        if contract.settlementStatus == 0:
                realisedPandL = pAndLDoNotPay
        if contract.settlementStatus == 1:
                realisedPandL = pAndLPay
        expectedPAndL = 'NA'
        if numberOfTrades > 0:
                expectedPAndL = pAndLPay*float(lastTradePrice)/100.0 + pAndLDoNotPay*float(100-lastTradePrice)/100.0

        # generate dictionary for the general information
        generalInfo = [{
                'name':contract.name,
                'expiry':contract.expiry.strftime("%d/%m/%Y %H:%M"),
                'description':contract.description,
                'issuer':contract.issuer.userBeingThisPlayer.username,
                'liquidityTokenHolder':liquidityToken.bid.player.userBeingThisPlayer.username,
                'liquidityTokenBid':liquidityToken.bid.price,
                'liquidityTokenOffer':liquidityToken.offer.price,
                'lastTradeDate': lastTradeDate,
                'lastTradePrice': lastTradePrice,
                'settlementStatus':contract.settlementStatus,
                'numberOfExchangedContracts':numberOfTrades,
                'numberOfBoughtContracts':len(contractsBoughtByPlayer),
                'averageBuyingPrice':bmean,
                'numberOfSoldContracts':len(contractsSoldByPlayer),
                'averageSellingPrice':smean,
                'expectedPAndL':expectedPAndL,
                'bestCasePAndL':max(pAndLPay, pAndLDoNotPay),
                'worstCasePAndL': min(pAndLPay, pAndLDoNotPay),
                'realisedPandL':realisedPandL
                }]

        return generalInfo, tradedContractList

        

#######################################################################################
# get all the information about the last visted contract of the player or nothing if there is no visited contract
def getSelectedContractInfo(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        player = player_list[0].dbPlayer
        # if the player has not visited ny contract yet, return empty
        lastVisitedContractList = LastVisitedContract.objects.filter( player = player )
        if len( lastVisitedContractList ) == 0:
                return { 'generalInfo':[{'empty':True}] }
        lastVisitedContract = lastVisitedContractList[0].contract
        
        #return generalInfo, tradedContractList
        tmp = getSelectedContractGeneralInfo( lastVisitedContract, player )

        tradedContractList = tmp[1]
        tradePricesHisto =  [ { 'tradeDate':trade.tradeDate.strftime("%d %B %H:%M"), 'tradePrice': trade.tradedPrice  } for trade in tradedContractList ]
        bidList = BidOnContract.objects.filter( contract = lastVisitedContract ).exclude(player=player).order_by('-price')
        formatedBidList = [ (b.player, b.price ) for b in bidList ]
        bidListOfList = [list(group) for key,group in itertools.groupby(formatedBidList,operator.itemgetter(1))]

        offerList = OfferOnContract.objects.filter( contract = lastVisitedContract ).exclude(player=player).order_by('price')
        formatedOfferList = [ (b.player, b.price ) for b in offerList ]
        offerListOfList = [list(group) for key,group in itertools.groupby(formatedOfferList,operator.itemgetter(1))]
        # generate dictionary for other player orders information
        orderBookInfo = [ { 'bidList'   : [ {'price': b[0][1], 'number': len(b) }  for b in bidListOfList ] ,
                            'offerList' : [ {'price': o[0][1], 'number': len(o) }  for o in offerListOfList ] } ]


        myBidList = BidOnContract.objects.filter( contract = lastVisitedContract, player=player ).order_by('-price')
        formatedMyBidList = [ (b.player, b.price ) for b in myBidList ]
        myBidListOfList = [list(group) for key,group in itertools.groupby(formatedMyBidList,operator.itemgetter(1))]

        myOfferList = OfferOnContract.objects.filter( contract = lastVisitedContract, player=player ).order_by('price')
        formatedMyOfferList = [ (b.player, b.price ) for b in myOfferList ]
        myOfferListOfList = [list(group) for key,group in itertools.groupby(formatedMyOfferList,operator.itemgetter(1))]

        # generate dictionary for current player orders information
        myOrders = [ {  'bidList'   : [ {'price': b[0][1], 'number': len(b) }  for b in myBidListOfList ] ,
                        'offerList' : [ {'price': o[0][1], 'number': len(o) }  for o in myOfferListOfList ] } ]
        
        return { 'generalInfo':tmp[0], 'tradePricesHisto': tradePricesHisto, 'orderBookInfo': orderBookInfo, 'myOrders':myOrders }


#######################################################################################
# get the general information about all the contracts
def getAllContractsInfo(request):
        player_list = [] #the player with a dummy initialisation
        alternative_response_list = [] #the answer to return if the player could not be authentificated with a dummy initialisation
        if not( authentificatePlayer( request, player_list, alternative_response_list ) ):
                return alternative_response_list[0]
        player = player_list[0].dbPlayer
        betroom = player.mainStrategy.betroom
        return { 'allContractInfo':[ {'info':getSelectedContractGeneralInfo(c, player)[0]}
                                             for c in DigitalContract.objects.filter( issuer__mainStrategy__betroom = betroom ) ] }
        





        
        
